module.exports = {


  friendlyName: 'Get priority vulnerabilities',


  description: 'Returns information about priority CVEs.',
  extendedDescription: 'This code was previously in the view action for the dashboard page, but was moved to a separate action to reduce inital page laoding time.',

  exits: {
    success: {
      outputType: [{}],
    },
  },


  fn: async function () {
    //  ┌─┐┌─┐┌┬┐  ┌─┐┬─┐┬┌─┐┬─┐┬┌┬┐┬ ┬  ┌─┐┬  ┬┌─┐  ┌─┐┬─┐┌─┐┌─┐┬─┐┌─┐┌─┐┌─┐
    //  │ ┬├┤  │   ├─┘├┬┘││ │├┬┘│ │ └┬┘  │  └┐┌┘├┤   ├─┘├┬┘│ ││ ┬├┬┘├┤ └─┐└─┐
    //  └─┘└─┘ ┴   ┴  ┴└─┴└─┘┴└─┴ ┴  ┴   └─┘ └┘ └─┘  ┴  ┴└─└─┘└─┘┴└─└─┘└─┘└─┘

    // Get the JSON array of Priority CVE IDs from the platform record.
    let platformRecord = await Platform.find({}).limit(1);
    let priorityVulnerabilities = platformRecord[0].priorityCveIds;
    let priorityVulnerabilitiesThatExistInTheDatabase = await Vulnerability.find({isPriority: true});
    let cveIdsThatDontExistInTheDatabase = _.difference(priorityVulnerabilities, _.pluck(priorityVulnerabilitiesThatExistInTheDatabase, 'cveId'));
    let priorityVulnPatchProgress = [];

    // Get patch progress for priority CVE IDs that only exist in the Platform record.
    for(let cve of cveIdsThatDontExistInTheDatabase){
      // Trim whitespace from the CVE ID. https://github.com/fleetdm/fleet/issues/14904
      let trimmedCveId = _.trim(cve);
      // Check to see if a Vulnerability record has been created for this CVE ID.
      let vulnRecordForThisCveExists = await Vulnerability.findOne({cveId: trimmedCveId, isPriority: false});
      if(vulnRecordForThisCveExists){// If we found a Vulnerability record that matches a CVE ID, we'll update it to have `isPriority: true`.
        let updatedVulnRecord = await Vulnerability.updateOne({id: vulnRecordForThisCveExists.id}).set({isPriority: true});
        priorityVulnerabilitiesThatExistInTheDatabase.push(updatedVulnRecord);
      } else {// Otherwise, we'll add 100% patch progress for this CVE.
        let patchProgress = {
          cveId: trimmedCveId,
          patchProgressPercentage: 100,
          additionalDetailsUrl: 'https://nvd.nist.gov/vuln/detail/'+ encodeURIComponent(cve),
        };
        priorityVulnPatchProgress.push(patchProgress);
      }
    }

    // Get patch progress for CVEs we have records for.
    for(let vuln of priorityVulnerabilitiesThatExistInTheDatabase) {
      let vulnPatchProgress = _.clone(vuln);
      vulnPatchProgress.affectedSoftware = [];
      // Calculate how many host have been affected by this vulnerability, and how many hosts are currently affected by this vulnerability
      let installsForThisVulnerability = await VulnerabilityInstall.find({vulnerability: vuln.id});
      // This number will represent the number of hosts that have been affected by the vulnerability.
      let uniqueAffectedHosts = _.uniq(_.pluck(installsForThisVulnerability, 'host'));
      // Get a list of software that is currently installed and affected by this vulnerability.
      let unresolvedInstallsForThisVuln = _.filter(installsForThisVulnerability, {uninstalledAt: 0});
      let unresolvedHosts = _.uniq(_.pluck(unresolvedInstallsForThisVuln, 'host'));
      let resolvedHosts = _.difference(uniqueAffectedHosts, unresolvedHosts);
      let uniqNumberOfResolvedInstallsForThisVuln = resolvedHosts.length;
      // Iterate through the installs for this vulnerability to build a list of software
      await sails.helpers.flow.simultaneouslyForEach(_.uniq(installsForThisVulnerability, 'fleetApid'), (install)=>{
        vulnPatchProgress.affectedSoftware.push({name: install.softwareName, version: install.versionName, url: sails.config.custom.fleetBaseUrl+'/software/'+install.fleetApid });
      });
      // Get the number of unique hosts who were previosuly affected by this vulnerability.
      vulnPatchProgress.numberOfHostsAffected = uniqueAffectedHosts.length;
      // To calculate the patch progress, we'll use the number of unique hosts who were previously affected by this vulnerability as the numerator and the number of unique hosts affected by the vulnerability as the denominator.
      vulnPatchProgress.patchProgressPercentage = Math.floor((uniqNumberOfResolvedInstallsForThisVuln / vulnPatchProgress.numberOfHostsAffected) * 100);
      priorityVulnPatchProgress.push(vulnPatchProgress);
    }//∞

    // Sort the priority vulnerabilities by CVE ID.
    priorityVulnPatchProgress = _.sortBy(priorityVulnPatchProgress, 'cveId');

    return priorityVulnPatchProgress;

  }


};
